package sysService

import (
	"context"
	"fmt"
	"gitee.com/jokces/kit/enum"
	"gitee.com/jokces/kit/errc"
	"gitee.com/jokces/kit/ginutil"
	sysModel "gitee.com/jokces/kit/global/admin/model"
	"gitee.com/jokces/kit/global/admin/token"
	"gitee.com/jokces/kit/global/admin/util"
	"gitee.com/jokces/kit/typ"
	"github.com/gin-gonic/gin"
	"strings"
	"time"
)

// RefreshToken 刷新token的处理
func (svc *Service) RefreshToken(ctx *gin.Context) (*sysModel.AccessTokenResp, error) {
	in := &sysModel.ReTokenReq{
		AppType: ctx.Param("appType"),
	}
	err := ginutil.ShouldBind(ctx, in)
	if err != nil {
		return nil, err
	}

	//逆向解析获取得到用户的ID
	tokenBo, b, err := token.ParseToken(in.RefreshToken)
	if err != nil {
		return nil, errc.ErrNeedLogin.MultiMsg("login out")
	}
	if !b {
		return nil, errc.ErrNeedLogin.MultiMsg("login out")
	}

	//默认的处理一个，就是总的服务
	cli, err := svc.ClientById(ctx, tokenBo.ClientId)
	if err != nil || cli == nil {
		return nil, errc.ErrAccessDenied.MultiMsg("非法客户端请求")
	}

	//获取原来的token ReTokenCache
	reOut := &sysModel.ReTokenCache{
		RefreshToken: in.RefreshToken,
	}
	key := reTokenKey(in.RefreshToken, in.AppType, tokenBo.ClientId, tokenBo.Id)
	if _, err := svc.r.SaveOrGetByJson(key, reOut, true, 0); err != nil {
		return nil, errc.ErrNeedLogin.MultiMsg("login out")
	}
	if reOut.Token == "" {
		return nil, errc.ErrNeedLogin.MultiMsg("login out")
	}
	switch in.AppType {
	case sysModel.ApiType:
		session, err := svc.AccountOne(ctx, &sysModel.AccountSession{Id: reOut.UserId})
		if err != nil {
			return nil, err
		}
		newToken, err := svc.refreshToken(reOut, cli, session)
		if err != nil {
			return nil, err
		}
		return newToken, nil
	case sysModel.AdminType:
		session, err := svc.AdminSession(ctx, reOut.UserId)
		if err != nil {
			return nil, err
		}
		session.GroupId = cli.ResourceIds
		newToken, err := svc.refreshToken(reOut, cli, session)
		if err != nil {
			return nil, err
		}
		return newToken, nil
	}
	return nil, errc.ErrNeedLogin.MultiMsg("not support")
}
func (svc *Service) refreshToken(in *sysModel.ReTokenCache, cli *sysModel.SysOauthClient, sess interface{}) (*sysModel.AccessTokenResp, error) {
	//处理老的token
	svc.expireOldToken(in.Token, in.AppType, cli.ClientId, in.UserId)

	//生成新的登录token
	newToken, err := token.GenerateToken(&token.Token{
		Id:       in.UserId,
		Exp:      time.Now().Unix() + int64(in.AccessTokenExpire),
		Typ:      in.NumberAppType(),
		ClientId: cli.ClientId,
	})
	if err != nil {
		return nil, errc.ErrInternalErr.MultiMsg("refresh error")
	}
	newTokenKey := tokenKey(newToken, in.AppType, cli.ClientId, in.UserId)
	if ok, err := svc.r.SaveOrGetByJson(newTokenKey, sess, false, time.Duration(in.AccessTokenExpire)*time.Second); err != nil {
		return nil, err
	} else if !ok {
		return nil, errc.ErrNeedLogin.MultiMsg("login out")
	}

	key := reTokenKey(in.RefreshToken, in.AppType, cli.ClientId, in.UserId)
	in.Token = newToken

	ttl, err := svc.withTll(key)
	if err != nil {
		return nil, errc.ErrInternalErr.MultiMsg("refresh error")
	}
	if err := svc.r.SetWithTTL(key, enum.ToJson(in), ttl); err != nil {
		return nil, errc.ErrInternalErr.MultiMsg("refresh error")
	}

	return &sysModel.AccessTokenResp{
		AccessToken: newToken,
		ExpiresIn:   int64(in.AccessTokenExpire),
	}, nil
}
func (svc *Service) withTll(key string) (time.Duration, error) {
	pttl := svc.r.PTTL(key)
	if pttl == nil || pttl.Err() != nil {
		return 0, errc.ErrInternalErr.MultiMsg("refresh error")
	}
	ttl, err := pttl.Result()
	if err != nil {
		return 0, errc.ErrInternalErr.MultiMsg("refresh error")
	}
	return ttl, nil
}

// 第一个为刷新token前缀
// 第二个为认证token前缀
func tokenPri(appType, clientId string, userId int64) (rePri string, accPri string) {
	if appType == sysModel.AdminType {
		rePri = sysModel.AdminRefreshToken
		accPri = sysModel.AdminToken
	} else {
		rePri = sysModel.ApiRefreshToken
		accPri = sysModel.ApiToken
	}
	rePri = fmt.Sprintf("%v:%v", rePri, userId)
	accPri = fmt.Sprintf("%v:%v", accPri, userId)
	if clientId != "" {
		rePri = fmt.Sprintf("%v:%v", rePri, clientId)
		accPri = fmt.Sprintf("%v:%v", accPri, clientId)
	}
	return rePri, accPri
}

// 生成对应的token的处理
// 前缀:用户ID:clientId:token
func reTokenKey(token, appType, clientId string, userId int64) string {
	if appType == sysModel.AdminType {
		return fmt.Sprintf("%v:%v:%v:%v", sysModel.AdminRefreshToken, userId, clientId, token)
	}
	return fmt.Sprintf("%v:%v:%v:%v", sysModel.ApiRefreshToken, userId, clientId, token)
}
func tokenKey(token, appType, clientId string, userId int64) string {
	if appType == sysModel.AdminType {
		return fmt.Sprintf("%v:%v:%v:%v", sysModel.AdminToken, userId, clientId, token)
	}
	return fmt.Sprintf("%v:%v:%v:%v", sysModel.ApiToken, userId, clientId, token)
}
func (svc *Service) expireOldToken(token, appType, clientId string, userId int64) {
	//获取以前的token
	old := tokenKey(token, appType, clientId, userId)

	//删除原来的KEY
	_, priKey := tokenPri(appType, clientId, userId)
	keys := svc.r.Keys(fmt.Sprintf("%v*", priKey))
	for _, delKey := range keys.Val() {
		if delKey == old {
			tll, _ := svc.withTll(old)
			if tll > 5*time.Minute {
				_ = svc.r.Expire(token, 5*time.Minute) //直接过期5min的有效期
			}
			continue
		}
		_ = svc.r.Del(delKey)
	}
}

// AuthorizationPass 授权码；账户的处理
// 兼容手机号|游戏|账号的匹配
func (svc *Service) AuthorizationPass(ctx *gin.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AuthorizationCodeResp, error) {
	rs := &sysModel.AuthorizationCodeResp{}
	if err := in.AuthPassParam(); err != nil {
		return rs, err
	}
	ch := &sysModel.AuthorizationCache{
		AppType:        in.AppType,
		AccessTokenReq: in,
	}
	switch in.AppType {
	case sysModel.AdminType:
		if client.NeedCheckCode() {
			if err := svc.CaptchaRedisVerify(in.Code, in.SessionId); err != nil {
				return rs, err
			}
		}
		pass, err := svc.UserPass(ctx, in)
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, client.ClientId)
		ch.UserId = pass.Id
		break
	case sysModel.ApiType:
		pass, err := svc.AccountPass(ctx, &sysModel.AccountSession{
			Email:    in.Email,
			Mobile:   typ.GlobalMobile(in.Phone),
			UserName: in.UserName,
		})
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, client.ClientId)
		ch.UserId = pass.Id
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	if ok, err := svc.r.SaveOrGetByJson(rs.Code, ch, false, 5*time.Minute); err != nil {
		return rs, err
	} else if ok {
		return rs, errc.ErrParamInvalid.MultiMsg("获取授权码失败")
	}
	return rs, nil
}
func (svc *Service) AuthorizationMobile(ctx *gin.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AuthorizationCodeResp, error) {
	rs := &sysModel.AuthorizationCodeResp{}
	if err := in.AuthMobileParam(); err != nil {
		return rs, err
	}

	if ok, err := svc.VerifySmsCode(typ.GlobalMobile(in.Phone), in.SessionId, in.Code, true); err != nil {
		return rs, err
	} else if !ok {
		return rs, errc.ErrParamInvalid.MultiMsg("短信验证码不正确")
	}

	ch := &sysModel.AuthorizationCache{
		AppType:        in.AppType,
		AccessTokenReq: in,
	}
	switch in.AppType {
	case sysModel.AdminType:
		pass, err := svc.UserOne(ctx, sysModel.SysUser{Phone: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, in.ClientId)
		ch.UserId = pass.Id
		break
	case sysModel.ApiType:

		pass, err := svc.AccountOne(ctx, &sysModel.AccountSession{Mobile: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, client.ClientId)
		ch.UserId = pass.Id
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	if ok, err := svc.r.SaveOrGetByJson(rs.Code, ch, false, 5*time.Minute); err != nil {
		return rs, err
	} else if ok {
		return rs, errc.ErrParamInvalid.MultiMsg("获取授权码失败")
	}
	return rs, nil
}
func (svc *Service) AuthorizationEmail(ctx *gin.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AuthorizationCodeResp, error) {
	rs := &sysModel.AuthorizationCodeResp{}
	if err := in.AuthEmailParam(); err != nil {
		return rs, err
	}
	if ok, err := svc.VerifyCode(in.Email, in.SessionId, in.Code, true); err != nil {
		return rs, err
	} else if !ok {
		return rs, errc.ErrParamInvalid.MultiMsg("短信验证码不正确")
	}

	ch := &sysModel.AuthorizationCache{
		AppType:        in.AppType,
		AccessTokenReq: in,
	}
	switch in.AppType {
	case sysModel.AdminType:
		pass, err := svc.UserOne(ctx, sysModel.SysUser{Phone: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, client.ClientId)
		ch.UserId = pass.Id
		break
	case sysModel.ApiType:
		pass, err := svc.AccountOne(ctx, &sysModel.AccountSession{Email: in.Email})
		if err != nil {
			return rs, err
		}
		//生成对应的code
		rs.Code = ginCode(pass.Id, in.AppType, in.GrantType, client.ClientId)
		ch.UserId = pass.Id
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	if ok, err := svc.r.SaveOrGetByJson(rs.Code, ch, false, 5*time.Minute); err != nil {
		return rs, err
	} else if ok {
		return rs, errc.ErrParamInvalid.MultiMsg("获取授权码失败")
	}
	return rs, nil
}
func (svc *Service) parseCode(code string) (*sysModel.AuthorizationCache, error) {
	out := &sysModel.AuthorizationCache{}
	if ok, err := svc.r.SaveOrGetByJson(code, out, true, 0); err != nil {
		return out, err
	} else if ok {
		return out, errc.ErrParamInvalid.MultiMsg("请重新授权")
	}
	return out, nil
}
func ginCode(userId int64, appType, grantType, clientId string) string {
	code := fmt.Sprintf("%v:%v:%v:%v:%v", userId, clientId, appType, grantType, time.Now().Unix())
	return util.Md516(code)
}

// UserPassLogin 登录的处理
func (svc *Service) UserPassLogin(ctx context.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AccessTokenResp, error) {
	rs := &sysModel.AccessTokenResp{}
	if err := in.AuthPassParam(); err != nil {
		return rs, err
	}

	reCache := &sysModel.ReTokenCache{
		ClientId:           client.ClientId,
		AccessTokenExpire:  client.AccessTokenValidity,
		RefreshTokenExpire: client.RefreshTokenValidity,
		AppType:            in.AppType,
	}

	switch in.AppType {
	case sysModel.AdminType:
		if client.NeedCheckCode() {
			if err := svc.CaptchaRedisVerify(in.Code, in.SessionId); err != nil {
				return rs, err
			}
		}
		pass, err := svc.UserPass(ctx, in)
		if err != nil {
			return rs, err
		}
		session, err := svc.AdminSession(ctx, pass.Id)
		if err != nil {
			return rs, err
		}
		//赋值权限ID
		session.GroupId = client.ResourceIds
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, session, rs); err != nil {
			return rs, err
		}
		break
	case sysModel.ApiType:
		pass, err := svc.AccountPass(ctx, &sysModel.AccountSession{UserName: in.UserName, Mobile: typ.GlobalMobile(in.Phone), Email: in.Email})
		if err != nil {
			return rs, err
		}
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, pass, rs); err != nil {
			return rs, err
		}
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	return rs, nil
}
func (svc *Service) UserMobileLogin(ctx context.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AccessTokenResp, error) {
	rs := &sysModel.AccessTokenResp{}
	if err := in.AuthMobileParam(); err != nil {
		return rs, err
	}

	if ok, err := svc.VerifySmsCode(typ.GlobalMobile(in.Phone), in.SessionId, in.Code, true); err != nil {
		return rs, err
	} else if !ok {
		return rs, errc.ErrParamInvalid.MultiMsg("验证码不正确")
	}

	reCache := &sysModel.ReTokenCache{
		ClientId:           client.ClientId,
		AccessTokenExpire:  client.AccessTokenValidity,
		RefreshTokenExpire: client.RefreshTokenValidity,
		AppType:            in.AppType,
	}

	switch in.AppType {
	case sysModel.AdminType:
		pass, err := svc.UserOne(ctx, sysModel.SysUser{Phone: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		session, err := svc.AdminSession(ctx, pass.Id)
		if err != nil {
			return rs, err
		}
		session.GroupId = client.ResourceIds
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, session, rs); err != nil {
			return rs, err
		}
		break
	case sysModel.ApiType:
		pass, err := svc.AccountOne(ctx, &sysModel.AccountSession{Mobile: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, pass, rs); err != nil {
			return rs, err
		}
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	return rs, nil
}
func (svc *Service) UserEmailLogin(ctx context.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AccessTokenResp, error) {
	rs := &sysModel.AccessTokenResp{}
	if err := in.AuthEmailParam(); err != nil {
		return rs, err
	}
	reCache := &sysModel.ReTokenCache{
		ClientId:           client.ClientId,
		AccessTokenExpire:  client.AccessTokenValidity,
		RefreshTokenExpire: client.RefreshTokenValidity,
		AppType:            in.AppType,
	}
	if ok, err := svc.VerifyCode(in.Email, in.SessionId, in.Code, true); err != nil {
		return rs, err
	} else if !ok {
		return rs, errc.ErrParamInvalid.MultiMsg("验证码不正确")
	}

	switch in.AppType {
	case sysModel.AdminType:
		pass, err := svc.UserOne(ctx, sysModel.SysUser{Phone: typ.GlobalMobile(in.Phone)})
		if err != nil {
			return rs, err
		}
		session, err := svc.AdminSession(ctx, pass.Id)
		session.GroupId = client.ResourceIds
		if err != nil {
			return rs, err
		}
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, session, rs); err != nil {
			return rs, err
		}
		break
	case sysModel.ApiType:
		pass, err := svc.AccountOne(ctx, &sysModel.AccountSession{Email: in.Email})
		if err != nil {
			return rs, err
		}
		if err := svc.tokenCreate(in.AppType, client.ClientId, pass.Id, client.RefreshTokenValidity, client.AccessTokenValidity, reCache, pass, rs); err != nil {
			return rs, err
		}
		break
	default:
		return nil, errc.ErrParamInvalid.MultiMsg("暂不支持")
	}

	return rs, nil
}
func (svc *Service) delOldToken(appType, clientId string, userId int64) error {
	priKey, rePriKey := tokenPri(appType, clientId, userId)
	if err := svc.r.ClearLikeKey(priKey); err != nil {
		return errc.ErrParamInvalid.MultiMsg("获取token失败")
	}
	if err := svc.r.ClearLikeKey(rePriKey); err != nil {
		return errc.ErrParamInvalid.MultiMsg("获取token失败")
	}
	return nil
}
func (svc *Service) tokenCreate(appType, clientId string, userId int64, reExp, exp int32, reCache *sysModel.ReTokenCache, sess interface{}, out *sysModel.AccessTokenResp) error {
	toTyp := token.SwapToTyp(appType)

	//删除原来的token
	if err := svc.delOldToken(appType, clientId, userId); err != nil {
		return err
	}

	//创建刷新token
	reToken, err := token.GenerateToken(&token.Token{
		Id:       userId,
		Exp:      time.Now().Unix() + int64(reExp),
		Typ:      toTyp,
		ClientId: clientId,
	})
	if err != nil {
		return err
	}

	//创建accessToken
	tk, err := token.GenerateToken(&token.Token{
		Id:       userId,
		Exp:      time.Now().Unix() + int64(exp),
		Typ:      toTyp,
		ClientId: clientId,
	})
	if err != nil {
		return err
	}
	out.AccessToken = tk
	out.RefreshToken = reToken
	out.ExpiresIn = int64(exp)

	reCache.UserId = userId
	reCache.AppType = appType
	reCache.RefreshToken = reToken
	reCache.Token = tk

	//保存session
	reKey := reTokenKey(reToken, appType, clientId, userId)
	if _, err := svc.r.SaveOrGetByJson(reKey, reCache, false, time.Duration(reExp)*time.Second); err != nil {
		return errc.ErrInternalErr.MultiMsg("login error")
	}
	tKey := tokenKey(tk, appType, clientId, userId)
	if _, err := svc.r.SaveOrGetByJson(tKey, sess, false, time.Duration(exp)*time.Second); err != nil {
		return errc.ErrInternalErr.MultiMsg("login error")
	}
	return nil
}

// AuthorizationCodeLogin 关于授权码的处理来获取
func (svc *Service) AuthorizationCodeLogin(ctx *gin.Context, in *sysModel.AccessTokenReq, client *sysModel.SysOauthClient) (*sysModel.AccessTokenResp, error) {
	if err := in.AuthClientCredentialsParam(); err != nil {
		return nil, err
	}
	if err := verifyClient(ctx, in.Code, client); err != nil {
		return nil, err
	}
	ch, err := svc.parseCode(in.Code)
	if err != nil {
		return nil, err
	}

	switch ch.GrantType {
	case sysModel.Password.ToString():
		return svc.UserPassLogin(ctx, in, client)
	case sysModel.Mobile.ToString():
		return svc.UserMobileLogin(ctx, in, client)
	case sysModel.Email.ToString():
		return svc.UserEmailLogin(ctx, in, client)
	case sysModel.Wechat.ToString():
		//小程序，等其他的登录方式
		break
	default:
		break
	}
	return nil, errc.ErrNotFound.MultiMsg("auth授权服务目前未开放")

}
func (svc *Service) AuthorizationCode(ctx *gin.Context, in *sysModel.AccessTokenReq, cli *sysModel.SysOauthClient) (*sysModel.AuthorizationCodeResp, error) {
	switch in.GrantType {
	case sysModel.Password.ToString():
		pass, err := svc.AuthorizationPass(ctx, in, cli)
		return pass, err
	case sysModel.Mobile.ToString():
		pass, err := svc.AuthorizationMobile(ctx, in, cli)
		return pass, err
	case sysModel.Email.ToString():
		pass, err := svc.AuthorizationEmail(ctx, in, cli)
		return pass, err
	case sysModel.Wechat.ToString():
		//TODO:
	default:
		ginutil.RespErr(ctx, errc.ErrNotFound.MultiMsg("目前还不支持"))
		break
	}
	return nil, nil
}

func verifyClient(ctx *gin.Context, code string, client *sysModel.SysOauthClient) error {
	header := ctx.GetHeader(sysModel.ClientHeader)
	if header == "" {
		return errc.ErrParamInvalid.MultiMsg("client header need")
	}
	//这个是采用对应的秘钥进行加密的算法处理
	//clientId:code:secret
	headerKey := fmt.Sprintf("%v:%v:%v", client.ClientId, code, client.ClientSecret)
	md5 := util.Md5(headerKey)
	if strings.ToLower(headerKey) != strings.ToLower(md5) {
		return errc.ErrParamInvalid.MultiMsg("client check failed")
	}
	return nil
}

// AccessToken 的解密处理
func (svc *Service) AccessToken(accessToken string) (*token.Token, error) {
	tk, b, err := token.ParseToken(accessToken)
	if err != nil || !b {
		return nil, errc.ErrNeedLogin.MultiMsg("请登录")
	}
	return tk, nil
}
func (svc *Service) GetTokenHeader(c *gin.Context) string {
	return c.GetHeader(sysModel.TokenHeader)
}
func (svc *Service) AdminSessionUser(tk *token.Token, accessToken string) (*sysModel.AdminUserToken, error) {
	sess := &sysModel.AdminUserToken{}
	key := tokenKey(accessToken, sysModel.AdminType, tk.ClientId, tk.Id)
	exist, err := svc.r.SaveOrGetByJson(key, sess, true, 0)
	if err != nil {
		return sess, err
	}
	if exist {
		return sess, nil
	} else {
		return sess, errc.ErrNeedLogin.MultiMsg("请登录")
	}
}
func (svc *Service) ApiSessionUser(tk *token.Token, accessToken string) (*sysModel.AccountSession, error) {
	sess := &sysModel.AccountSession{}
	key := tokenKey(accessToken, sysModel.ApiType, tk.ClientId, tk.Id)
	exist, err := svc.r.SaveOrGetByJson(key, sess, true, 0)
	if err != nil {
		return sess, err
	}
	if exist {
		return sess, nil
	} else {
		return sess, errc.ErrNeedLogin.MultiMsg("请登录")
	}
}
func (svc *Service) GetApiUser(c *gin.Context) (bool, sysModel.AccountSession) {
	rs := &sysModel.AccountSession{}
	u, exists := c.Get(sysModel.TokenHeader)
	if exists {
		rs = u.(*sysModel.AccountSession)
	}
	return exists, *rs
}
func (svc *Service) GetAdminUser(c *gin.Context) (bool, sysModel.AdminUserToken) {
	rs := &sysModel.AdminUserToken{}
	u, exists := c.Get(sysModel.TokenHeader)
	if exists {
		rs = u.(*sysModel.AdminUserToken)
	}
	return exists, *rs
}

// LoginOut 退出登录的处理
func (svc *Service) LoginOut(accessToken string) error {
	tk, b, err := token.ParseToken(accessToken)
	if err != nil {
		return err
	}
	if !b {
		return nil
	}
	appType := sysModel.AdminType
	if tk.Typ == 2 {
		appType = sysModel.ApiType
	}
	if err := svc.delOldToken(appType, tk.ClientId, tk.Id); err != nil {
		return errc.ErrNeedLogin.MultiMsg("退出登录失败")
	}
	return nil
}
func (svc *Service) UserLoginLimit(userId int64, appType string) error {
	if err := svc.delOldToken(appType, "", userId); err != nil {
		return errc.ErrNeedLogin.MultiMsg("限制登录异常")
	}
	return nil
}

func (svc *Service) AdminTokenList(page *typ.PageReq) (*typ.ListResp, error) {
	rs := &typ.ListResp{}
	list := make([]*sysModel.RedisTokenResp, 0)

	key := fmt.Sprintf("%v", sysModel.AdminType)

	rsKeys, ml, err := svc.tokenListRedis(page, key)
	if err != nil {
		return rs, err
	}
	if rsKeys == nil {
		return rs, nil
	}

	for _, rsKey := range rsKeys {
		out := &sysModel.AdminUserToken{}
		ok, err := svc.r.SaveOrGetByJson(rsKey, out, false, 0)
		if err != nil {
			return rs, err
		}
		if ok {
			list = append(list, &sysModel.RedisTokenResp{
				Token:    rsKey,
				UserId:   out.Id,
				Uid:      out.Uid,
				Email:    out.Email,
				Mobile:   out.Phone,
				UserName: out.UserName,
			})
		}
	}
	rs.Count = ml
	rs.List = list
	return rs, nil
}
func (svc *Service) ApiTokenList(page *typ.PageReq) (*typ.ListResp, error) {
	rs := &typ.ListResp{}
	list := make([]*sysModel.RedisTokenResp, 0)

	key := fmt.Sprintf("%v", sysModel.ApiToken)

	rsKeys, ml, err := svc.tokenListRedis(page, key)
	if err != nil {
		return rs, err
	}
	if rsKeys == nil {
		return rs, nil
	}

	for _, rsKey := range rsKeys {
		out := &sysModel.AccountSession{}
		ok, err := svc.r.SaveOrGetByJson(rsKey, out, false, 0)
		if err != nil {
			return rs, err
		}
		if ok {
			list = append(list, &sysModel.RedisTokenResp{
				Token:    rsKey,
				UserId:   out.Id,
				Uid:      out.Uid,
				Email:    out.Email,
				Mobile:   out.Mobile,
				UserName: out.UserName,
			})
		}
	}
	rs.Count = ml
	rs.List = list
	return rs, nil
}
func (svc *Service) tokenListRedis(page *typ.PageReq, key string) ([]string, int64, error) {
	keys := svc.r.Keys(key)
	if keys == nil {
		return nil, 0, nil
	}
	result, err := keys.Result()
	if err != nil {
		return nil, 0, err
	}
	limit, start := page.LimitStart()
	limit = start + limit
	ml := len(result)
	if ml == 0 || ml < limit || start < ml {
		return nil, int64(ml), nil
	}
	rsKeys := result[start:limit]
	return rsKeys, int64(ml), nil
}

// CheckToken 检查token
func (svc *Service) CheckToken(accessToken string) (*sysModel.CheckTokenResp, error) {
	rs := &sysModel.CheckTokenResp{}
	tk, b, err := token.ParseToken(accessToken)
	if err != nil {
		return rs, err
	}
	if !b {
		return rs, errc.ErrNeedLogin.MultiMsg("已过期")
	}
	appType := sysModel.AdminType
	if tk.Typ == 2 {
		appType = sysModel.ApiType
	}
	orgToken := tokenKey(accessToken, appType, tk.ClientId, tk.Id)

	tll, err := svc.withTll(orgToken)
	if err != nil {
		return rs, err
	}
	rs.NowTime = time.Now().Unix()
	rs.ExpiresAt = rs.NowTime + (tll.Milliseconds() / 1000) //毫秒变成秒
	return rs, nil
}
